#pragma once
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<unistd.h>

using namespace std;

namespace ns_thread_pool
{
    template<class T>
    class ThreadPool
    {
    public:
        ThreadPool(int num = 5)
            :_num(num)
        {
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);

            _tid.resize(num);
            for(int i = 0; i < num; i++)
            {
                pthread_create(&_tid[i], nullptr, Rountine, (int*)this);
            }
        }
        ~ThreadPool()
        {
            for(int i = 0; i < _num; i++)
            {
                pthread_join(_tid[i], nullptr);
            }

            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }
        //在类中让线程执行类成员方法，是不可行的，因为类成员函数都隐含由this指针
        //必须让线程执行静态方法
        static void* Rountine(void* args)
        {
            ThreadPool<T>* tp = (ThreadPool<T>*)args;
            while(1)
            {
                tp->Lock();
                while(tp->IsEmpty())
                {
                    //任务队列为空，让线程挂起
                    tp->Wait();
                }
                //该任务队列中一定有一个任务了
                T t;
                tp->PopTask(&t);
                tp->Unlock();

                t.run();
            }
        }
        void PushTask(const T& in)
        {
            Lock();
            _task_queue.push(in);
            Unlock();
            //有任务了，唤醒一个线程
            WakeUp();
        }
        void PopTask(T* out)
        {
            *out = _task_queue.front();
            _task_queue.pop();
        }

        bool IsEmpty()
        {
            return _task_queue.empty();
        }
    private:
        void Lock()
        {
            pthread_mutex_lock(&_mtx);
        }
        void Unlock()
        {
            pthread_mutex_unlock(&_mtx);
        }
        void Wait()
        {
            pthread_cond_wait(&_cond, &_mtx);
        }
        void WakeUp()
        {
            pthread_cond_signal(&_cond);
        }
    private:
        int _num;//线程数量
        queue<T> _task_queue;//任务队列,该成员是一个临界资源
        vector<pthread_t> _tid;

        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
    };
}